#include "listwindow.h"
#include "twl_keys.h"
using std::string;

// wuz TOPMOST | TOOLWINDOW
ListWindow::ListWindow(const char* caption, bool clear_list)
		: TEventWindow((char*)caption,NULL,TOOLWINDOW),      
           m_is_editable(false), m_clear_list(clear_list)
{
		   Layout (this) << Listbox(100,(EH)on_list_click) << NamedAs(&m_ls);
}

// overrides TEventWindow::size() 
// used to resize the list box to fill the client area
void ListWindow::size()
{
  Rect rt;
  get_rect(rt,true);
  m_ls->resize(0,0,rt.right - rt.left,rt.bottom - rt.top);
}


// overrides TEventWindow::keydown()
// It's only used when this object is in editable mode
// This is passed the virtual key code @vkey of any
// key pressed and catches the INSERT and DELETE keys.
// on_delete() usually returns true, but you can prevent deletion
// by returning false; the object is disposed of.
// on_insert() must return a new object which can present itself as text;
// returning NULL means that the derived class doesn't want to insert.
void ListWindow::keydown(int vkey)
{
  int idx = m_ls->selected();
  if (! m_is_editable) return;
  ItemObject* obj;
//  if (vkey == VK_F12) update();
//  else
  if (vkey == VK_INSERT) {
      attempt_insert(idx);
  }
  else if (vkey == VK_DELETE && idx != -1) {
      obj = data(idx);
      if (on_delete(idx,obj)) {
        m_ls->remove(idx);
        delete obj;
      }
  }
}

void ListWindow::attempt_insert(int idx)
{
   if (idx == -1) idx = m_ls->selected();
   ItemObject* obj;
   if ((obj = on_insert(idx)) != NULL) {
        m_ls->insert(idx,"");
        if (idx == -1) idx = m_ls->count()-1;
        m_ls->set_data(idx,obj);
        update_item(idx);
   }
}

// a handler for notifications (of kind @code) from the list box
// We're currently only interested in the double-click event,
// which fires the action of the associated object.
// It also calls double_clicked(), which is usually overriden
// by derived classes if they wish to perform some additional action.
void ListWindow::on_list_click(int code)
{
  if (code == LIST_DOUBLE_CLICK) {
     int idx = m_ls->selected();
     if (idx == -1) return;
     ItemObject* obj = data(idx);
  	 if (obj) obj->action();
 	 double_clicked(idx,obj);
  }
}

// clear the list, deleting any associated objects!
void ListWindow::clear()
{
      for(int i = 0, n = m_ls->count(); i < n; i++) {
            ItemObject* p = data(i);
            delete p;
      }
      m_ls->clear();
}

// puts us into editable mode, which means we will
// respond to the INSERT and DELETE keys.
void ListWindow::set_editable()
{
  m_is_editable = true;
  view_child_messages(true);
}

// return the associated list data at @idx
ItemObject* ListWindow::data(int idx)
{
  return (ItemObject*)m_ls->get_data(idx);
}

// update the text of a list item at @idx with @text,
// preserving any associated data.
void ListWindow::update_item_text(int idx, string newstr)
{
    ItemObject* obj = data(idx);
    m_ls->remove(idx);
    m_ls->insert(idx,(char*)newstr.c_str());
    m_ls->set_data(idx,obj);
}

// these three methods are simple wrappers around the TListBox calls
// of the same name.
void ListWindow::add(string s, ItemObject* obj)
{
    m_ls->add((char*)s.c_str(),obj);
}

void ListWindow::redraw(bool yesno)
{
    m_ls->redraw(yesno);
}

int  ListWindow::count()
{
  return m_ls->count();
}

// update a list item at @idx by asking the associated object
// to supply the text
void ListWindow::update_item(int idx)
{
    string str;
    data(idx)->as_str(str);
    update_item_text(idx,str);
}

void ListWindow::add(ItemObject* obj)
{
   add("",obj);
   update_item(count()-1);
}
// given text @s, and some delimiting character @delim,
// fill the list by splitting the text.
void ListWindow::split_text(string s, char delim)
{
    char* reslt = (char*)s.c_str();
    char* p = strtok(reslt,"\n");
    while (p) {
         add(p,NULL);
         p = strtok(NULL,"\n");
    }
}

// this is meant to be called by the client whenever the client
// wishes the list contents to change.  It usually empties the
// list and calls fill_list(), but it can be overriden.
void ListWindow::update()
{
   if (m_clear_list) clear();
   fill_list();
}

// this fills the list with items. It's usually overriden in derived classes,
// but this base version relies on the item objects' (optional!) ability to generate
// their own text.
void ListWindow::fill_list()
{
  redraw(false);
  for (int i = 0; i < count(); i++)
   update_item(i);
  redraw(true);
}


////// WindowList //////////////
// WindowList is a simple container of window objects, which has two uses:
// (1) you can show or hide a group of windows with one call.
// (2) the dimensions of these windows can be automatically saved.
WindowList::WindowList(IniFile* ini)
: m_ini(ini),m_count(0),m_visible(false)
{
  if (m_ini)
	m_file_bounds = new FormOptions(0,m_ini);
  else
    m_file_bounds = NULL;   
}

void WindowList::add(TWin* w)
{
    if (m_count < MAX_WINDOWS)
	  m_windows[m_count++] = w;
}

void WindowList::remove(TWin* w)
{
//  for(int i = 0; i < m_count; i++)
//	  if (m_windows[i] == w)
}

TWin* WindowList::window(int i)
{ 
  if (i > 0 && i < m_count)
      return m_windows[i];
  else return NULL;
}

bool WindowList::visible()
{
  return m_visible;
}
void WindowList::show()
{
 	for(int i = 0; i < m_count; i++) {
		TWin* w = m_windows[i];
		w->show(1); 
        w->on_top();
    }
    m_visible = true;
}

void WindowList::hide()
{
 	for(int i = 0; i < m_count; i++) {
		TWin* w = m_windows[i];
		w->show(0); 
    }
    m_visible = false;
}


void WindowList::restore()
{
    for(int i = 0; i < m_count; i++) {
          m_file_bounds->set_form(m_windows[i]);
          m_file_bounds->read();
    }
}

void WindowList::save()
{
    for(int i = 0; i < m_count; i++) {
          m_file_bounds->set_form(m_windows[i]);
          m_file_bounds->write();
          m_file_bounds->clear_form();
    }
}
